#include "GDT.h"
#include "../IO/Terminal.h"
#include "../Helpers/StringHelpers.h"

namespace System{
    GlobalDescriptorTable::GlobalDescriptorTable(IO::Terminal *terminal){
        _terminal = terminal;

        char buffer[16];
        Helpers::StringHelpers::IntToString((uint32_t)&pointer, 16, buffer);
        *_terminal << "GDT pointer at: 0x" << buffer << "\n";

        pointer.limit = (sizeof(gdt_entry_t) * 5) - 1;
        pointer.base  = (uint32_t)&entries;
    
        SetGate(0, 0, 0, 0, 0);                // Null segment
        SetGate(1, 0, 0xFFFFFFFF, 0x9A, 0xCF); // Code segment
        SetGate(2, 0, 0xFFFFFFFF, 0x92, 0xCF); // Data segment
        SetGate(3, 0, 0xFFFFFFFF, 0xFA, 0xCF); // User mode code segment
        SetGate(4, 0, 0xFFFFFFFF, 0xF2, 0xCF); // User mode data segment
        
        ::flush_gdt((uint32_t)&pointer);
    }

    void GlobalDescriptorTable::SetGate(int32_t num, uint32_t base, uint32_t limit, uint8_t access, uint8_t granularity){
        entries[num].base_low = base&0xffff;
        entries[num].base_middle = (base>>16)&0xFF;
        entries[num].base_high = (base>>24)&0xFF;
        entries[num].limit_low = limit&0xFFFF;
        entries[num].access = access;
        entries[num].granularity=(limit>>16)&0x0F;
        entries[num].granularity|=granularity&0xF0;
    }
}
